﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace RingControls
{
    public class RingPanel : Panel
    {
        #region ContentsVerticalAlignment
        public static DependencyProperty ContentsVerticalAlignmentProperty = DependencyProperty.Register(
            "ContentsVerticalAlignment",
            typeof(ContentsVerticalAlignment),
            typeof(RingPanel),
            new PropertyMetadata(ContentsVerticalAlignment.Center));

        public ContentsVerticalAlignment ContentsVerticalAlignment
        {
            get { return (ContentsVerticalAlignment)GetValue(ContentsVerticalAlignmentProperty); }
            set { SetValue(ContentsVerticalAlignmentProperty, value); }
        }

        #endregion

        #region ContentsDirection
        public static DependencyProperty ContentsDirectionProperty = DependencyProperty.Register(
            "ContentsDirection",
            typeof(ContentsDirection),
            typeof(RingPanel),
            new PropertyMetadata(ContentsDirection.Orthogonal));

        public ContentsDirection ContentsDirection
        {
            get { return (ContentsDirection)GetValue(ContentsDirectionProperty); }
            set { SetValue(ContentsDirectionProperty, value); }
        }
        #endregion

        protected override System.Windows.Size MeasureOverride(System.Windows.Size availableSize)
        {
            var childMeasure = new Size(double.PositiveInfinity, double.PositiveInfinity);

            foreach (var child in Children)
            {
                child.Measure(childMeasure);
            }
            return availableSize;
        }

        protected override System.Windows.Size ArrangeOverride(System.Windows.Size finalSize)
        {
            if (Children.Count == 0)
                return finalSize;

            Rect layoutRect;
            if (finalSize.Height < finalSize.Width)
            {
                layoutRect = new Rect(
                    (finalSize.Width - finalSize.Height) / 2,
                    0,
                    finalSize.Height,
                    finalSize.Height);
            }
            else
            {
                layoutRect = new Rect(
                    0,
                    (finalSize.Height - finalSize.Width) / 2,
                    finalSize.Width,
                    finalSize.Width);
            }

            double angle = 0.0;
            foreach (var child in Children)
            {
                var group = new TransformGroup();
                if (ContentsDirection == ContentsDirection.Vertical)
                {
                    group.Children.Add(new RotateTransform()
                    {
                        Angle = -angle,
                        CenterX = child.DesiredSize.Width / 2,
                        CenterY = child.DesiredSize.Height / 2
                    });
                }
                group.Children.Add(new RotateTransform()
                {
                    Angle = angle,
                    CenterX = child.DesiredSize.Width / 2,
                    CenterY = finalSize.Height / 2 - layoutRect.Top + GetContentVerticalOffset(child.DesiredSize.Height)
                });
                group.Children.Add(new TranslateTransform()
                {
                    X = layoutRect.Left + (layoutRect.Width - child.DesiredSize.Width) / 2,
                    Y = layoutRect.Top - GetContentVerticalOffset(child.DesiredSize.Height)
                });
                child.RenderTransform = group;

                child.Arrange(new Rect(new Point(0, 0), child.DesiredSize));

                angle += 360.0 / Children.Count;
            }

            return finalSize;
        }

        private double GetContentVerticalOffset(double h)
        {
            double offset = 0.0;
            switch (ContentsVerticalAlignment)
            {
                case ContentsVerticalAlignment.Bottom:
                    offset = h;
                    break;
                case ContentsVerticalAlignment.Center:
                    offset = h / 2.0;
                    break;
                case ContentsVerticalAlignment.Top:
                    offset = 0;
                    break;
                default:
                    break;
            }

            return offset;
        }
    }
}
